package com.gitee.feizns.dynamic.reflect;

import com.gitee.feizns.dynamic.Ex;
import lombok.SneakyThrows;

import java.lang.reflect.Constructor;
import java.util.Deque;

/**
 * 构造器操作工具类
 * @author feizns
 * @since 2019/5/19 0019
 */
public abstract class Constructors {

    /**
     * <b>使用参数params实例化type类型</b>
     * @param type {@link Class}
     * @param params 参数列表
     * @param <T> 需要实例化的类型
     * @return 对应类型的实例
     */
    @SneakyThrows
    public static <T> T newInstance(Class<T> type, Object... params) {
        return of(type, Classes.of(params).toArray(new Class<?>[]{})).newInstance(params);
    }

    /**
     * <b>获取对应参数的公共构造方法</b>
     * @param type 类型
     * @param parameterTypes 参数类型
     * @return {@link Constructor}
     */
    @SneakyThrows
    public static <T> Constructor<T> of(Class<T> type, Class<?>... parameterTypes) {
        return type.getConstructor(parameterTypes);
    }

    /**
     * 找到可以调用单个参数构造函数
     * @param type 类型
     * @param parameterType 参数类型
     * @return {@link Constructor}<{@link T}>
     */
    public static <T> Constructor<T> findCanInvokeSingleParameterConstructor(Class<T> type, Class<?> parameterType) {
        Deque<Class<?>> classesAndInterfaces = Classes.ofClassesAndInterfaces(parameterType);
        while ( !classesAndInterfaces.isEmpty() ) {
            Class<?> remove = classesAndInterfaces.remove();
            Constructor<T> result = Ex.tryCatch(() -> of(type, remove))
                    .ignoreException(NoSuchMethodException.class)
                    .orElse(null);
            if ( result != null )
                return result;
        }
        return null;
    }

}
